package com.onadake.web.controller.user;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.onadake.domain.query.Records;
import com.onadake.utils.Dates;
import com.onadake.utils.Dates.Month;
import com.onadake.web.domain.ChatMessage;
import com.onadake.web.domain.RequestErrors;

/**
 * This is controller which provides data for user dashboard.
 * 
 * @author radek.hecl
 *
 */
@Controller
@RequestMapping("/user")
public class UserDashboardController {

    /**
     * Builder object.
     */
    public static class Builder {

        /**
         * Builds the result object.
         * 
         * @return created object
         */
        public UserDashboardController build() {
            return new UserDashboardController(this);
        }
    }

    // TODO - remove me
    private Random random = new Random();

    /**
     * Constructor to allow frameworks creating new instance.
     */
    @SuppressWarnings("unused")
    private UserDashboardController() {
    }

    /**
     * Creates new instance.
     * 
     * @param builder builder object
     */
    public UserDashboardController(Builder builder) {
        guardInvariants();
    }

    /**
     * Guards this object to be consistent. Throws exception if this is not the case.
     */
    @PostConstruct
    private void guardInvariants() {
    }

    /**
     * Selects records with friends of the logged in user.
     * 
     * @return records with friends
     */
    @RequestMapping(value = "/selectFriends", method = { RequestMethod.POST, RequestMethod.GET })
    @ResponseBody
    public Records<Map<String, String>> selectFriends() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        Map<String, String> rec1 = new HashMap<>();
        rec1.put("code", "US0000000000001");
        rec1.put("nick", "Prdlavka");
        Map<String, String> rec2 = new HashMap<>();
        rec2.put("code", "US0000000000002");
        rec2.put("nick", "Boris");
        Map<String, String> rec3 = new HashMap<>();
        rec3.put("code", "US0000000000003");
        rec3.put("nick", "Krtecek");

        return new Records.Builder<Map<String, String>>().
                setNumRecords(3).
                addRecord(rec1).
                addRecord(rec2).
                addRecord(rec3).
                build();
    }

    /**
     * Selects records with messages. Ordering of the messages is by insert timestamp descendant (first record has highest one).
     * 
     * @param model model object from which filter will be constructed
     * @return records with messages
     */
    @RequestMapping(value = "/selectMessages", method = { RequestMethod.POST, RequestMethod.GET })
    @ResponseBody
    public Records<ChatMessage> selectMessages(@ModelAttribute ChatMessageFilterModel model) {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        
        return new Records.Builder<ChatMessage>().
                setNumRecords(5000).
                addRecord(new ChatMessage.Builder().
                        setOwnerCode("US0000000000003").
                        setText("Me too!!!").
                        setUtcInsertTimestamp(Dates.getFormattedDate(Dates.createTime(2012, Month.JANUARY, 1, 12, 36, 37),
                                "yyyy/MM/dd HH:mm:ss.SSS")).
                        build()).
                addRecord(new ChatMessage.Builder().
                        setOwnerCode("US0000000000002").
                        setText("I am fine, than you").
                        setUtcInsertTimestamp(Dates.getFormattedDate(Dates.createTime(2012, Month.JANUARY, 1, 12, 25, 21),
                                "yyyy/MM/dd HH:mm:ss.SSS")).
                        build()).
                addRecord(new ChatMessage.Builder().
                        setOwnerCode("US0000000000001").
                        setText("Hello body, how are you").
                        setUtcInsertTimestamp(Dates.getFormattedDate(Dates.createTime(2012, Month.JANUARY, 1, 12, 23, 30),
                                "yyyy/MM/dd HH:mm:ss.SSS")).
                        build()).
                build();
    }

    /**
     * Selects the records with live messages. Ordering of the messages is by insert timestamp descendant (first record has highest one).
     * 
     * @param latestUtcInsertTimestamp latest UTC zone insert timestamp which is in the format yyyy/MM/dd HH:mm:ss.SSS,
     *     only the records with insert timestamp greater than this will be selected
     * @return record with the new messages
     */
    @RequestMapping(value = "/selectLiveMessages", method = { RequestMethod.POST, RequestMethod.GET })
    @ResponseBody
    public Records<ChatMessage> selectLiveMessages(@RequestParam("latestUtcInsertTimestamp") String latestUtcInsertTimestamp) {
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        
        if (random.nextDouble() > 0.8) {
            Date date = DateUtils.addSeconds(Dates.getDateFromString(latestUtcInsertTimestamp, "yyyy/MM/dd HH:mm:ss.SSS"), 10);
            String id = RandomStringUtils.random(1, "123");
            return new Records.Builder<ChatMessage>().
                    setNumRecords(1).
                    addRecord(new ChatMessage.Builder().
                            setOwnerCode("US000000000000" + id).
                            setText("Heya!!!").
                            setUtcInsertTimestamp(Dates.getFormattedDate(date, "yyyy/MM/dd HH:mm:ss.SSS")).
                            build()).
                    build();
        }
        else {
            return new Records.Builder<ChatMessage>().
                    setNumRecords(0).
                    build();
        }
    }

    /**
     * Posts the message.
     * 
     * @return empty JSON object on success or error JSON in case of validation failure 
     */
    @RequestMapping(value = "/postMessage", method = RequestMethod.POST)
    @ResponseBody
    public Object postMessage(@ModelAttribute PostMessageModel model) {
        System.out.println(model);
        if (model.getText().equals("error-file")) {
            return new RequestErrors.Builder().
                    addNamedFieldError("messageFile", "Sample error").
                    build();
        }
        if (model.getText().equals("error-text")) {
            return new RequestErrors.Builder().
                    addNamedFieldError("messageText", "Sample error").
                    build();
        }
        return "{}";
    }
    
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}
